<template>
  <!-- 登录限制 -->
  <div class="login-limit">
    <el-dialog :model-value="showDialog" title="登录客群限制" width="380px" :close-on-click-modal="false" :before-close="close">
      <el-form :model="form" ref="formRef" style="min-height: 60px;">
        <el-form-item label="类型">
          <el-radio-group v-model="form.type">
            <el-radio label="white">
              白名单
            </el-radio>
            <el-radio label="black">
              黑名单
            </el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="客群" prop="userListIds" :rules="[{ required: true, trigger: 'blur', message: '请选择客群' }]">
          <!--    选择框-->
          <div ref="scSelectorRef" class="sc-selector-holder" @click="clickSelector">
            <div class="sc-selector-holder-content">
              <span v-show="selectedTreeItems.length == 0">请选择</span>
              <div v-show="selectedTreeItems.length > 0">
                <el-tag v-for="item in selectedTreeItems" closable @close="handleDeleteSelect(item)" disable-transitions>
                  <div style="width:140px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">{{ item[treeLabelKey] }}</div>
                </el-tag>
              </div>
            </div>
            <div class="selector-expand-indicator" :class="{
              'selector-expand-indicator__reverse': selectorPopoverVisible,
            }">
              <el-icon color="#A8ABB2">
                <ArrowDown />
              </el-icon>
            </div>
          </div>
          <!--  弹出框-->
          <div class="sc-selector-popover" ref="scSelectorPopover" v-if="selectorPopoverVisible">
            <div class="dropdown-list">
              <div class="top-filter">
                <div class="selector-item filter filter-input">
                  <el-input style="width: 100%" v-model="inputValue" :validate-event="false" v-bind="inputPropsMixed" />
                </div>
                <div class="selector-item filter filter-tag" v-if="filterTags.length > 0">
                  <el-check-tag :checked="selectedTag.has(item.val)"
                    @change="(check) => handleTagCheckChange(check, item.val)" :key="item.val" v-for="item in filterTags">
                    {{ item.name }}
                  </el-check-tag>
                </div>
              </div>

              <div class="selector-item sc-selector-list">
                <el-tree v-if="sectionList.length" ref="treeRef" :data="sectionList" :expand-on-click-node="false"
                  empty-text="" v-bind="treePropsMixed">
                  <template #default="{ node, data }">
                    <div class="tree-item-wrapper" @click="handleTreeItemClick({ node, data })">
                      <slot name="tree-item" :data="data" :node="node">
                        <div style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;" :class="{
                          'words-selected': selectedTreeItems.find(
                            (item) =>
                              deepGet(item, treeNodeKey) == deepGet(data, treeNodeKey)
                          )
                        }">
                          {{ data.name }}
                        </div>
                        <!-- <selector-item :data="data" :is-selected="selectedTreeItems.find(
                          (item) =>
                            deepGet(item, treeNodeKey) ==
                            deepGet(data, treeNodeKey)
                        )
                          " :words="data[treeLabelKey]" :highlight-words="highlightWords" /> -->
                      </slot>
                    </div>
                  </template>
                </el-tree>

                <div ref="pageEndIndicator" class="sc-selector-page-end-indicator">
                  <span v-if="loadingData">正在加载...</span>
                  <span v-else-if="!loadingData && sectionList.length == 0">暂无数据</span>
                  <span v-else-if="finished">已全部加载</span>
                  <span v-else style="cursor: pointer" @click="clickPageEndIndicator">点击加载下一页</span>
                </div>
              </div>
            </div>
          </div>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button type="default" @click="close">
          关闭
        </el-button>
        <el-button type="primary" @click="submit">
          确定
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { request } from "@/utils/request";
const props = defineProps({
  showDialog: {
    type: Boolean,
    default: false
  }
})
const formRef = ref()
const form = reactive({
  type: 'white',
  userListIds: []
})

const selectedTreeItems = ref<Array<any>>([])

const filterTags = ref([{ val: 1, name: '智能客群' }, { val: 0, name: '静态客群' }])

const emits = defineEmits(['update:showDialog', 'confirm'])
const close = () => {
  formRef.value?.resetFields()
  selectedTreeItems.value = []
  sectionList.value = []
  emits('update:showDialog', false)
}
const submit = () => {
  form.userListIds = selectedTreeItems.value
  formRef.value?.validate((valid: boolean) => {
    const phoneLoginWhitelist = form.type == 'white' ? form.userListIds : []
    const phoneLoginBlacklist = form.type == 'black' ? form.userListIds : []
    if (valid) {
      emits('confirm', { phoneLoginWhitelist, phoneLoginBlacklist })
      close()
    }
  })
}
//编辑回显
const getSelectedTreeItems = async (data: { list: string, type: 1 | 2 }) => {
  const arrIds = data.list.split(',')
  if (data.type == 1) {
    form.type = 'black'
  } else if (data.type == 2) {
    form.type = 'white'
  }
  selectedTreeItems.value = [];
  let idLen = arrIds.length
  if (!idLen) {
    return
  }
  let list = []
  const rs: any = await request("/user/userGroup/userGroupList", {
    type: '',
    name: '',
    currentPage: -1,
    showCount: -1,
  });
  if (rs.code == 200) {
    list = rs.payload ?? []
    for (let i = 0; i < list.length; i++) {
      if (idLen > 0) {
        if (arrIds.includes(String((list[i].id)))) {
          selectedTreeItems.value.push(list[i])
          idLen--
          continue
        }
      } else {
        break
      }
    }
  }
}

// input 过滤器
const inputValue: Ref<string> = ref("");

const inputPropsMixed = computed(() => {
  return {
    placeholder: "请输入后搜索",
  };
});
const sectionList = ref<any[]>([]);
// 数据处理
const loadingData = ref(false);
const finished = ref(false);
const pager = ref({
  currentPage: 0,
  showCount: 20,
});
const treePropsMixed = computed(() => {
  // TODO DeepMerge
  return {
    nodeKey: "id",
    props: {
      label: "name",
      children: "children",
    },
  };
});

const selectorPopoverVisible = ref(false);

watch(selectorPopoverVisible, (newValue) => {
  if (newValue) {
    nextTick(() => {
      _loadData(true)
      watchPageEnd();
      closeableGlobally();
    });
  }
});
const closeableGlobally = () => {
  document.addEventListener(
    "click",
    () => {
      selectorPopoverVisible.value = false;
    },
    {
      once: true,
    }
  );
};
// 分页，加载下一页
const pageEndIndicator = ref();
let intersectionObserver: IntersectionObserver;
const watchPageEnd = () => {
  // scLog("开始监听分页加载情况");
  intersectionObserver = new IntersectionObserver(function (entries) {
    // scLog("intersectionObserver triggered");
    const entry = entries[0];
    if (entry.isIntersecting) {
      // scLog("页尾相交");
      if (!loadingData.value) {
        // scLog("相交且未正在加载，开始加载下一页数据");
        _loadData();
      } else {
        // scLog("已经有正在加载的数据，取消本次加载触发");
      }
    } else {
    }
  });

  intersectionObserver.observe(pageEndIndicator.value);
};


const handleTreeItemClick = ({ node, data }: any) => {
  selectedTreeItems.value.push(data);
};
const treeLabelKey: ComputedRef<string> = computed(() => {
  return treePropsMixed.value.props?.label ?? "label";
});
// 树状列表节点唯一Key
const treeNodeKey: ComputedRef<string> = computed(() => {
  return treePropsMixed.value["nodeKey"] ?? "id";
});
const treeRef = ref();


// tag过滤器
const selectedTag: Ref<Set<string | number>> = ref(new Set());

const scSelectorRef = ref(); // 展示框ref
const scSelectorPopover = ref(); // 下拉列表ref

const clickSelector = () => {
  selectorPopoverVisible.value = !selectorPopoverVisible.value;
};

const deepGet = (obj: any, keys: any, defaultVal = "") => {
  return (
    (!Array.isArray(keys)
      ? keys.replace(/\[/g, ".").replace(/\]/g, "").split(".")
      : keys
    ).reduce((o, k) => (o || {})[k], obj) || defaultVal
  );
};

const handleDeleteSelect = (treeItemData: any) => {
  selectedTreeItems.value.splice(
    selectedTreeItems.value.findIndex(
      (item) =>
        deepGet(item, treeNodeKey.value) ==
        deepGet(treeItemData, treeNodeKey.value)
    ),
    1
  );
};

const clickPageEndIndicator = () => {
  _loadData();
};
watch(inputValue, (newValue) => {
  handleInputChange(newValue);
});
let debounceTimer: ReturnType<typeof setTimeout>;
const handleTagCheckChange = (status: boolean, item: any) => {
  if (status) {
    clearTimeout(debounceTimer);
    debounceTimer = setTimeout(() => {
      _loadData(true, item)
    }, 700);
    selectedTag.value = new Set([item]); 
  }else{
    selectedTag.value.clear();
  }
};

const handleInputChange = (value: string) => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(async () => {
    await _loadData(true);
  }, 700);
};

const _loadData = async (refresh = false, type = '') => {
  if (loadingData.value) {
    return;
  }
  if (refresh) {
    finished.value = false;
    pager.value.currentPage = 1;
    sectionList.value = [];
  } else {
    if (finished.value) {
      // scLog("已经全部加载完成");
      return;
    }
    pager.value.currentPage++;
  }

  loadingData.value = true;
  const rs: any = await request("/user/userGroup/userGroupList", {
    type: type,
    name: inputValue.value,
    currentPage: pager.value.currentPage,
    showCount: pager.value.showCount,
  });
  if (rs.code == 200) {
    if (rs.page.currentPage == 1) {
      if (refresh) {
        scSelectorPopover.value
          .getElementsByClassName("dropdown-list")[0]
          .scrollTo(0, 0);
      }
      sectionList.value = rs.payload || [];
    } else sectionList.value = sectionList.value.concat(rs.payload || []);
    if (rs.page.totalPage === pager.value.currentPage) finished.value = true;
    else finished.value = false;
  }

  loadingData.value = false;
}
defineExpose({ getSelectedTreeItems })
</script>
<style scoped lang="scss">
.words-selected {
  color: var(--el-color-primary);
}

.sc-selector {
  position: relative;
}

.sc-selector-holder {
  width: 214px;
  padding: 0 11px;
  position: relative;
  display: inline-flex;
  box-sizing: border-box;
  border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
  box-shadow: 0 0 0 1px var(--el-border-color) inset;
  vertical-align: middle;
  font-size: 14px;
  line-height: 32px;
  color: var(--el-input-text-color, var(--el-text-color-regular));
  cursor: pointer;
  transition: var(--el-transition-box-shadow);

  .selector-expand-indicator {
    display: inline-flex;
    align-items: center;
    transition: all linear 300ms;
  }

  .selector-expand-indicator__reverse {
    transform: rotate(180deg);
  }
}

.sc-selector-holder__focus {
  box-shadow: 0 0 0 1px var(--el-border-color-focus) inset;
}

.sc-selector-holder__hover {
  box-shadow: 0 0 0 1px var(--el-border-color-hover) inset;
}

.sc-selector-holder-content {
  flex: 1;
  width: 0;

  :deep(.el-tag) {
    margin-right: 10px;
  }

  span {
    color: #a8abb2;
  }

  .sc-selector-input-text {
    width: 100%;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
  }
}

.selector-item:not(:last-of-type) {
  margin-bottom: 12px;
}

.sc-selector-list {
  :deep(.tree-item-wrapper) {
    flex: 1;
    width: 0;
  }
}

.sc-selector-popover {
  position: absolute;
  bottom: 0;
  left: 0;
  transform: translateY(calc(100% + 12px));
  z-index: 1000;

  .dropdown-list {
    height: 300px;
    background: white;
    overflow: auto;
    box-shadow: var(--el-box-shadow-light);
    padding: 0 12px;
    max-width: 250px;
  }

  .selector-expand-pop {
    min-width: 10px;
    min-height: 10px;
    padding: 15px;
    position: absolute;
    top: 0;
    right: 0;
    transform: translateX(calc(100% + 12px));
    background: white;
    border-radius: 8px;
    box-shadow: var(--el-box-shadow-light);
    display: none;
  }
}

.sc-selector-popover:after {
  content: "";
  width: 0;
  height: 0;
  border-top: solid 6px transparent;
  border-right: solid 6px transparent;
  border-bottom: solid 6px white;
  border-left: solid 6px transparent;
  position: absolute;
  top: 0;
  left: 104px;
  transform: translateY(-100%);
}

.top-filter {
  position: sticky;
  top: 0;
  left: 0;
  z-index: 1;
  width: 100%;
  background: white;
  padding-top: 6px;
  padding-bottom: 6px;

  .filter-tag {
    overflow-x: auto;
    white-space: nowrap;

    .el-check-tag {
      margin-right: 3px;
    }
  }
}

.section-item {
  cursor: pointer;

  .section-title {
    display: flex;
    align-items: center;
    padding: 6px 0;

    .icon {
      width: 4px;
      height: 14px;
      background: var(--el-color-primary);
    }

    .content {
      margin: 0 4px;
    }

    .split-line {
      flex: 1;
      height: 1px;
      background: var(--el-color-info);
    }
  }
}

.sc-selector-page-end-indicator {
  //background: red;
  height: 45px;
  color: var(--el-color-primary);
  padding-top: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: default;
}

.disabled {
  background: #F4F6F9;
}
</style>